#ifndef _SYNCUP_H
#define _SYNCUP_H_

#include <async_queue.h>
#include <stdio.h>
#include <glib.h>

enum syncup_event_type {
    SC_EVENT_LABEL_PATH,
    SC_EVENT_FSNOTIFY,
    SC_EVENT_SYNC,
    SC_EVENT_NUM
};

typedef void (*syncup_evt_hdlr_t)(void *);

/**
 * @brief syncup event structure
 */
struct syncup_event {
    enum syncup_event_type type; /**< Event type */
    void *data; /**< Data to pass to \a handler */
    /** Event handler, which is called with \a data as argument */
    syncup_evt_hdlr_t handler;
    /**
     * Finalizer is called after \a handler finished to reclaim the resource
     * of \a data
     */
    syncup_evt_hdlr_t finalizer;
};

extern struct syncup_event *syncup_event_new(enum syncup_event_type type, void *data, syncup_evt_hdlr_t hdlr, syncup_evt_hdlr_t flzr);
extern void syncup_event_free(struct syncup_event *event);
/**
 * @brief Push \c syncup_event to internal event queue
 * @note Thread-safe
 */
extern void syncup_event_push(struct syncup_event *event);

/**
 * @brief Pop \c syncup_event from internal event queue
 *
 * This functions may block until there are new events to pop.
 * @note Thread-safe
 */
extern struct syncup_event *syncup_event_pop();
/**
 * @brief Dispatch \c syncup_event for execution
 *
 * The \c syncup_event is dispatched to the specified thread for execution
 * according to its \c syncup_event_type. Events of the same type must be
 * handled by identical thread sequentially, but events of different types
 * may be dispatched to different thread.
 */
extern void syncup_event_dispatch(struct syncup_event *event);



struct syncup {
    char *local_home;
    //char *local_root;
    char *remote_home;
    char *remote_root;

    struct async_queue evt_queue;

    FILE *log;
};

extern struct syncup *syncup;

#define SYNCUP_HOME_DIR ".syncup"
#define SYNCUP_HOME_DIR_LEN (sizeof (SYNCUP_HOME_DIR) - 1)
#define SYNCUP_LOG_NAME "syncup.log"

extern void syncup_init();
extern void syncup_run();
extern void syncup_end();

extern void syncup_label_path(const char *path);
extern void syncup_add_file_to_db(char *name, uint32_t parent_inode, GString *path);
extern int syncup_add_path_to_db_recursively(char *name, uint32_t parent_inode, GString *path);

/**
 * @name Private platform specific functions
 *
 * These functions are not for direct invocation.
 */
/*@{*/
extern void daemonize();
extern void syncup_service_platform_init();
extern void syncup_service_platform_end();
/*@}*/

#endif /* ! _SYNCUP_H */
